#pragma once

#include <iostream>
#include <string>

#include "log.hpp"

#include <cstring>

#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>

Log log;

struct msg_buf
{
    long mtype;
    char mtext[1024];
};

class Message_Queue
{
    enum Message_Queue_Error
    {
        KEY_GET_ERROR = 1,
        Message_Queue_CREAT_ERROR = 2,
        Message_Queue_LOAD_ERROR = 3,
        Message_Queue_UNLOAD_ERROR = 4,
        Message_Queue_DELETE_ERROR = 5,
        Message_Queue_Control_ERROR = 6
    };

    static key_t get_key()
    {
        const std::string pathname("/home/qyc");
        const int proj_id = 0x6666;
        
        key_t key = ftok(pathname.c_str(), proj_id);
        if (key < 0)
        {
            log(Fatal, "ftok error: %s", strerror(errno));
            exit(KEY_GET_ERROR);
        }
        log(Info, "ftok success, key is 0x%x", key);
        return key;
    }
public:
    static int get(int flag = IPC_CREAT)
    {
        constexpr int Message_Queue_SIZE = 4096;

        key_t key = get_key();
        int msgid = msgget(key, flag);
        if (msgid < 0)
        {
            log(Fatal, "message queue creat error: %s", strerror(errno));
            exit(Message_Queue_CREAT_ERROR);
        }
        log(Info, "message queue creat success, msgid: %d", msgid);
        return msgid;
    }

    static int creat()
    {
        return get(IPC_CREAT | IPC_EXCL | 0666);
    }

    static void send(int msgid, const void* msgp, int msgflg = 0)
    {
        if (msgsnd(msgid, msgp, sizeof(msg_buf), msgflg) < 0)
        {
            log(Fatal, "message queue send error: %s", strerror(errno));
            exit(Message_Queue_LOAD_ERROR);
        }
        log(Info, "message queue send success");
    }

    static void recieve(int msgid, void* msgp, long msgtyp, int msgflg = MSG_NOERROR)
    {
        if (msgrcv(msgid, msgp, sizeof(msg_buf), msgtyp, msgflg) < 0)
        {
            log(Fatal, "message queue recieve error: %s", strerror(errno));
            exit(Message_Queue_UNLOAD_ERROR);
        }
        log(Info, "message queue recieve success");
    }

    static void state(int msgid, msqid_ds* buf)
    {
        if (msgctl(msgid, IPC_STAT, buf) < 0)
        {
            log(Fatal, "message queue control error: %s", strerror(errno));
            exit(Message_Queue_Control_ERROR);
        }
        log(Info, "message queue control success, msgid: %d", msgid);
    }

    static void free(int msgid)
    {
        if (msgctl(msgid, IPC_RMID, nullptr) < 0)
        {
            log(Fatal, "message queue delete error: %s", strerror(errno));
            exit(Message_Queue_DELETE_ERROR);
        }
        log(Info, "message queue delete success, msgid: %d", msgid);
    }
};